#include <cmath>
#include <assert.h>

template<class T>
class Matrix;

template<class T>
class Vec4f {
  
public:

	// Constructors & Destructor
	Vec4f() { _data[0] = _data[1] = _data[2] = _data[3] = static_cast<T>(0); }

	Vec4f(T d0, T d1, T d2, T d3)
	{
		_data[0] = d0;
		_data[1] = d1;
		_data[2] = d2;
		_data[3] = d3;
	}

	// 数据访问
	const T& operator[](int i) const
	{
		assert(IsIndexCurrent(i));
	    return _data[i];
	}

	T& operator[](int i)
	{
		assert(IsIndexCurrent(i));
		return _data[i];
	}

	T x() const { return _data[0]; }
	T y() const { return _data[1]; }
	T z() const { return _data[2]; }
	T w() const { return _data[3]; }
	int r() const { return static_cast<int>(_data[0]) % 255; }
	int g() const { return static_cast<int>(_data[1]) % 255; }
	int b() const { return static_cast<int>(_data[2]) % 255; }
	int a() const { return static_cast<int>(_data[3]) % 255; }

	T Length() const
	{
		T len = sqrt( static_cast<T>(_data[0] * _data[0] + _data[1] * _data[1] +
			_data[2] * _data[2] + _data[3] * _data[3]) );
	return len;
	}

	// 转换
	void Scale(T d0, T d1, T d2, T d3)	// 缩放
	{
		_data[0] *= d0;
		_data[1] *= d1;
		_data[2] *= d2;
		_data[3] *= d3;
	}
	void Normalize()					// 转化为单位向量
	{
		T l = Length();
		if (l > 0) {
			_data[0] /= l;
			_data[1] /= l;
			_data[2] /= l;
		}
	}

	// OVERLOADED OPERATORS
	Vec4f& operator=(const Vec4f &rhs)
	{
		_data[0] = rhs._data[0];
		_data[1] = rhs._data[1];
		_data[2] = rhs._data[2];
		_data[3] = rhs._data[3];
		return *this;
	}

	bool operator==(const Vec4f &rhs) const
	{
		return ((_data[0] == rhs._data[0]) &&
            (_data[1] == rhs._data[1]) &&
			(_data[2] == rhs._data[2]) &&
			(_data[3] == rhs._data[3]));
	}

	bool operator!=(const Vec4f& rhs) const
	{
		return !((*this) == rhs);
	}
	Vec4f& operator+=(const Vec4f& rhs)
	{
		_data[0] += rhs._data[0];
		_data[1] += rhs._data[1];
		_data[2] += rhs._data[2];
		_data[3] += rhs._data[3];
		return *this;
	}
	Vec4f& operator-=(const Vec4f& rhs)
	{
		_data[0] -= rhs._data[0];
		_data[1] -= rhs._data[1];
		_data[2] -= rhs._data[2];
		_data[3] -= rhs._data[3];
		return *this;
	}
	Vec4f& operator*=(const T& rhs)
	{
		_data[0] *= rhs;
		_data[1] *= rhs;
		_data[2] *= rhs;
		_data[3] *= rhs;
		return *this;
	}
	Vec4f& operator/=(const T& rhs)
	{
		_data[0] /= rhs;
		_data[1] /= rhs;
		_data[2] /= rhs;
		_data[3] /= rhs;
		return *this;
	}
	const Vec4f operator+(const Vec4f &rhs) const
	{
		Vec4f result;
		result._data[0] = _data[0] + rhs._data[0];
		result._data[1] = _data[1] + rhs._data[1];
		result._data[2] = _data[2] + rhs._data[2];
		result._data[3] = _data[3] + rhs._data[3];
		return result;
	}
	const Vec4f operator-(const Vec4f &rhs) const
	{
		Vec4f result;
		result._data[0] = _data[0] - rhs._data[0];
		result._data[1] = _data[1] - rhs._data[1];
		result._data[2] = _data[2] - rhs._data[2];
		result._data[3] = _data[3] - rhs._data[3];
		return result;
	}
	const Vec4f operator*(const T& rhs) const
	{
		Vec4f result;
		result._data[0] = _data[0] * rhs;
		result._data[1] = _data[1] * rhs;
		result._data[2] = _data[2] * rhs;
		result._data[3] = _data[3] * rhs;
		return result;
	}
	const Vec4f operator/(const T& rhs) const
	{
		Vec4f result;
		result._data[0] = _data[0] / rhs;
		result._data[1] = _data[1] / rhs;
		result._data[2] = _data[2] / rhs;
		result._data[3] = _data[3] / rhs;
		return *this;
	}
	void Transform(const Matrix<T>& mat) {
		Vec4f answer;
		for (int x = 0; x < 4; x++) {
			answer._data[x] = 0;
			for (int i = 0; i < 4; i++) {
				answer._data[x] += mat._data[x][i] * _data[i];
			}
		}
		(*this) = answer;
	}

private:
	friend class Matrix;
	friend const Vec4f operator/(T& lhs, const Vec4f& rhs)
	{
		return rhs / lhs;
	}

	friend const Vec4f operator*(T& lhs, const Vec4f& rhs)
	{
		return rhs * lhs;
	}

	bool IsIndexCurrent(int i) const
	{
		if (i < 0 || i >= 4)
			return false;
		else
			return true;
	}
	// REPRESENTATION
	T _data[4];
};
